
package com.studiofortress.sf.util.structure;

import com.studiofortress.sf.graphics.GLTexture;
import com.studiofortress.sf.graphics.GraphicsGL;

/**
 * This image class has an added angle so it can be drawn at an angle and
 * automatic movement code. Once setup, this will move on it's own each time
 * it's act method is called. If act is overriden then you must either call up
 * to this act method or call the actMove method instead.
 *
 * @author Joseph Lenton - JosephLenton@StudioFortress.com
 */
public class MovingImageActor<G extends GraphicsGL> extends ImageActor<G>
{
    private float angle;
    private float angleDegrees;
    
    private float moveX;
    private float moveY;
    
    /**
     * Creates a new moving image actor that by default does not move and has no
     * image.
     */
    public MovingImageActor()
    {
        super();
    }

    /**
     * Creates a new actor which by default will display using the given image.
     * @param img The starting image for this actor. Null for no image.
     */
    public MovingImageActor(GLTexture img)
    {
        super( img );
    }

    /**
     * Creates a new MovingImageActor that is located at the given position.
     * @param x The x location of the actor.
     * @param y The y location of the actor.
     */
    public MovingImageActor(float x, float y)
    {
        this( null, x, y );
    }

    /**
     * Creates a new MovingImageActor that will start with the given image and
     * location.
     * @param img The image for this actor, null for no image.
     * @param x The x location for this actor to start at.
     * @param y The y location for this actor to start at.
     */
    public MovingImageActor(GLTexture img, float x, float y)
    {
        super( img, x, y );
    }
    
    /**
     * Note that this has no impact on the movement of this actor.
     * @param angle The angle to point towards, in radians.
     */
    public void setAngle(float angle)
    {
        this.angle = angle;
        this.angleDegrees = (float) Math.toDegrees( angle );
    }

    /**
     * @return The angle this actor is pointing at in radians.
     */
    public float getAngle()
    {
        return angle;
    }

    /**
     * @return The angle of this actor in degrees.
     */
    public float getAngleDegrees()
    {
        return angleDegrees;
    }

    /**
     * The same as calling setMoveX and setMoveY. This sets the amount to
     * automatically move by when actMove is called.
     *
     * This is typically to be used if you want the actor to move in a specific
     * direction regardless of their angle (i.e. move to the right of the screen
     * regardless of how they are pointed).
     *
     * @param moveX The amount to move along the x axis.
     * @param moveY The amount to automatically move along the y axis.
     */
    public void setMove(float moveX, float moveY)
    {
        setMoveX( moveX );
        setMoveY( moveY );
    }

    /**
     * Sets the angle to the given angle, and then sets the auto movement code
     * for this actor to move towards that angle at the given speed.
     *
     * This is typically to be used when you want the actor to move in regards
     * to their current angle.
     * 
     * @param angle The angle to move towards.
     * @param speed The speed to move at.
     */
    public void setMoveAngle(float angle, float speed)
    {
        setAngle( angle );
        setMove( (float) (speed*Math.cos(angle)), (float) (speed*Math.sin(angle)) );
    }

    /**
     * @return The amount that this actor is moving by on each frame along the x-axis.
     */
    public float getMoveX()
    {
        return moveX;
    }

    /**
     * @return The amount that this actor is moving along the y-axis by on each frame.
     */
    public float getMoveY()
    {
        return moveY;
    }

    /**
     * @param moveX The amount to move by on each frame along the x axis.
     */
    public void setMoveX(float moveX)
    {
        this.moveX = moveX;
    }

    /**
     * @param moveY The amount to move by on each from, along the y axis.
     */
    public void setMoveY(float moveY)
    {
        this.moveY = moveY;
    }
    
    /**
     * Updates the movement code and calls for it's super class to update too.
     * If this is overridden then future developers can call to move through the
     * actMove method.
     */
    @Override
    public void act()
    {
        actMove();
        super.act();
    }
    
    /**
     * Moves by the amounts returned from getMoveX and getMoveY.
     */
    protected void actMove()
    {
        move( getMoveX(), getMoveY() );
    }
    
    /**
     * Paints this actors image at it's current angle to the graphics given, if
     * there is an image.
     * @param g The graphics object to draw too.
     */
    @Override
    public void paint(G g)
    {
        final GLTexture img = getImage();
        if (img != null) {
            g.drawTexture( img, getX(), getY(), true, - getAngleDegrees() );
        }
    }
}
